package cn.kimmking.research.qedis.core.opr;

import cn.kimmking.research.qedis.core.AbstractOperator;

import java.util.*;

/**
 * Set operators.
 *
 * @Author : kimmking(kimmking@apache.org)
 * @create 2024/6/11 下午8:05
 */
public class SetOperator extends AbstractOperator {

    public int sadd(String key, String... values) {
        CacheEntry<?> entry = getOrInitCacheEntry(key);
        LinkedHashSet<String> exist = (LinkedHashSet<String>) entry.getValue();
        exist.addAll(List.of(values));
        return values.length;
    }

    public int srem(String key, String... values) {
        if(checkInvalid(key) || values == null || values.length == 0) return 0;
        LinkedHashSet<String> exist = (LinkedHashSet<String>) getEntryValue(key);
        long count = Arrays.stream(values).filter(exist::remove).count();
        return (int)count;
    }

    public String spop(String key) {
        if(checkInvalid(key)) return null;
        LinkedHashSet<String> exist = (LinkedHashSet<String>) getEntryValue(key);
        Object[] array = exist.toArray();
        if(array.length > 0) {
            Object rnd = array[new Random().nextInt(array.length)];
            if(exist.remove(rnd)) {
                return (String) rnd;
            }
        }
        return null;
    }

    public String[] smembers(String key) {
        if(checkInvalid(key)) return new String[0];
        LinkedHashSet<String> exist = (LinkedHashSet<String>) getEntryValue(key);
        return exist.toArray(new String[exist.size()]);
    }

    public int sismember(String key, String value) {
        if(checkInvalid(key)) return 0;
        LinkedHashSet<String> exist = (LinkedHashSet<String>) getEntryValue(key);
        return exist.contains(value) ? 1 : 0;
    }

    public int scard(String key) {
        if(checkInvalid(key)) return 0;
        LinkedHashSet<String> exist = (LinkedHashSet<String>) getEntryValue(key);
        return exist.size();
    }

    private CacheEntry<?> getOrInitCacheEntry(String key) {
        CacheEntry<?> entry = getEntry(key);
        if(entry == null) {
            synchronized (getMap()) {
                if((entry = getEntry(key)) == null) {
                    entry = new CacheEntry<>(new LinkedHashSet<String>(), System.currentTimeMillis(), -1000);
                    putEntry(key, entry);
                }
            }
        }
        return entry;
    }

}
